package defectsim;

import java.text.SimpleDateFormat;
import java.util.Calendar;

import repast.simphony.space.continuous.NdPoint;
import repast.simphony.space.grid.GridPoint;

public class Util {

	private static final String DATE_FORMAT_NOW = "dd_MM_yyyy_HH_mm_ss";

	public static double calculateDistance(NdPoint p1, NdPoint p2){

		double distance = Math.sqrt((Math.pow(p1.getY() - p2.getY(), 2) + 
				Math.pow(p1.getX() - p2.getX(), 2)));

		return distance;
	}
	// Minimum image convention
	public static double calculateMICDistance(NdPoint p1, NdPoint p2, double length){

		double xx = p2.getX() - p1.getX();
		double yy = p2.getY() - p1.getY();
		double dx = xx - length * Math.round(xx / length);
		double dy = yy - length * Math.round(yy / length);

		return Math.sqrt(dx * dx + dy * dy);
	}

	public static double calculateMICDistance(GridPoint p1, GridPoint p2, int length){

		double xx = p2.getX() - p1.getX();
		double yy = p2.getY() - p1.getY();
		double dx = xx - length * Math.round(xx / length);
		double dy = yy - length * Math.round(yy / length);

		return Math.sqrt(dx * dx + dy * dy);
	}

	public static double calculateMICLength(double x1, double x2, double length){

		return (x2 - x1) - length * Math.round((x2 - x1) / length);
	}

	public static int calculateMICLength(int x1, int x2, int length){

		return (x2 - x1) - length * Math.round((x2 - x1) / length);
	}

	public static double calculateAngle(NdPoint p1, NdPoint p2){

		double dx;
		double dy;

		dx = p2.getX() - p1.getX();
		dy = p2.getY() - p1.getY();
		double angle = StrictMath.atan2(dy, dx);
		while(0 > angle) {
			angle += 2.0 * Math.PI;
		}

		return angle;
	}

	public static double calculateAngle(double dx, double dy){

		double angle = StrictMath.atan2(dy, dx);
		while(0 > angle) {
			angle += 2.0 * Math.PI;
		}

		return angle;
	}
	
	public static double calculateMICAngle(NdPoint p1, NdPoint p2, double length){
		double xx = p2.getX() - p1.getX();
		double yy = p2.getY() - p1.getY();
		double dx = xx - length * Math.round(xx / length);
		double dy = yy - length * Math.round(yy / length);
		double angle = StrictMath.atan2(dy, dx);
		while(0 > angle) {
			angle += 2.0 * Math.PI;
		}

		return angle;
	}

	/**
	 * Converts grid point to continuous space point 
	 * @param gridPoint to be converted
	 * @param scale between grid and continuous space dimensions
	 * @return continuous space point
	 */
	public static NdPoint convertToNdPoint(GridPoint gridPoint, double scale){
		return new NdPoint(gridPoint.getX() / scale, gridPoint.getY() / scale);
	}

	/**
	 * Converts continuous space point to grid point 
	 * @param ndPoint to be converted
	 * @param scale between grid and continuous space dimensions
	 * @return grid point
	 */
	public static GridPoint convertToGridPoint(NdPoint ndPoint, double scale){
		return new GridPoint((int)(ndPoint.getX() * scale), (int)(ndPoint.getY() * scale));
	}

	public static String now() {
		Calendar cal = Calendar.getInstance();
		SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW);
		return sdf.format(cal.getTime());

	}

	/**
	 * Calculates power of negative numbers, ignores the imaginary part
	 * @param number
	 * @param x
	 * @return real part of complex number if number is negative
	 */
	public static double complexPower(double number, double x){
		double result = 0.0; 
		if (number < 0.0){
			double re = number;
			double im = 0.0;
			double modulus = Math.sqrt(re*re + im*im);
			double arg = Math.atan2(im,re);
			double log_re = Math.log(modulus);
			double log_im = arg;
			double x_log_re = x * log_re;
			double x_log_im = x * log_im;
			double modulus_ans = Math.exp(x_log_re);
			result = modulus_ans * Math.cos(x_log_im);
		}
		else
			result = Math.pow(number, x);

		return result;
	}

	public static double erfc(double x){

		double t;
		double z;

		double errfunc;

		z = Math.abs(x);
		t = 1.0 / ( 1.0 + 0.5 * z );

		errfunc = t * Math.exp( -z * z - 1.26551223 + t * ( 1.00002368 + t * ( 0.37409196 + t *
				( 0.09678418 + t * (-0.18628806 + t * ( 0.27886807 + t * (-1.13520398 + t *	
						( 1.48851587 + t * (-0.82215223 + t * 0.17087277 )))))))));

		if (x < 0) 
			errfunc = 2.0 - errfunc;

		return errfunc;
	}

}
